#pragma once

#include <ir/ir.h>
#include <ir/inst.h>
#include <ir/block.h>
#include <ir/reg.h>
#include <ir/array_info.h>
#include <type.h>

namespace ir {
  class Genarator;

  class Genarator {
  public:
    Genarator(CompUnit * comp_unit);
    ~Genarator() = default;

    Func * create_func(const std::string & name, VarType func_type);
    Reg * gen_inst_imm(Block & block, VarType reg_type, int int_number);
    Reg * gen_inst_imm(Block & block, VarType reg_type, float float_number);
    Reg * gen_inst_arg_alloc(Func & func, VarType type);
    Reg * gen_inst_alloc(Block & block, VarType type);
    void gen_inst_store(Block & block, Reg * rd, Reg * src);
    Reg * gen_inst_load(Block & block, Reg * src);
    Reg * gen_inst_array_alloc(Block & block, VarType type, uint32_t count);
    void gen_inst_array_store(Block & block, Reg * rd, Reg * src, Reg * index);
    Reg * gen_inst_array_load(Block & block, Reg * src, Reg * index);
    GlobalReg * gen_inst_global_alloc(VarType type, std::string iden, int int_number);
    GlobalReg * gen_inst_global_alloc(VarType type, float float_number);
    void gen_inst_global_store(Block & block, GlobalReg * global_rd, Reg * src);
    Reg * gen_inst_global_load(Block & block, GlobalReg * global_src);
    Reg * gen_inst_i32_to_f32(Block & block, Reg * src);
    Reg * gen_inst_f32_to_i32(Block & block, Reg * src);
    Reg * gen_inst_call(Block & block, Func * func, std::vector<Reg*> args);
    void gen_inst_ret(Block & block, VarType type, Reg * reg);
    Reg * gen_inst_add(Block & block, Reg * src1, Reg * src2);
    Reg * gen_inst_sub(Block & block, Reg * src1, Reg * src2);
    Reg * gen_inst_mul(Block & block, Reg * src1, Reg * src2);
    Reg * gen_inst_div(Block & block, Reg * src1, Reg * src2);
    void gen_inst_jmp(Block & block, Block * block_dst);
    void gen_inst_bne(Block & block, Reg * src1, Reg * src2, Block * block_dst);
    void gen_inst_beq(Block & block, Reg * src1, Reg * src2, Block * block_dst);

    Block * create_block(Func & func);
    Block * create_begin_block(Func & func);
    Reg * create_arg(Func & func, VarType var_type);
    Reg * create_reg(Block & block, VarType var_type);
    ArrayInfo * create_array(Func & func, ArrayType & arr_size);
    GlobalReg * create_global_reg(std::string iden, VarType type);

  private:
    ir::CompUnit * comp_unit;

    int block_i;
    int reg_i;
  };
}
